package org.finesys.auth.configure;


import org.finesys.common.constants.SecurityConstants;
import org.finesys.common.security.authentication.configurer.FormIdentityLoginConfigurer;
import org.finesys.common.security.authentication.filter.PasswordDecoderFilter;
import org.finesys.common.security.authentication.generator.CustomeOAuth2AccessTokenGenerator;
import org.finesys.common.security.authentication.generator.CustomeOAuth2TokenCustomizer;
import org.finesys.common.security.authorization.AuthenticationProvidersCustomCustomizer;
import org.finesys.common.security.authorization.OAuth2ClientAuthenticationConfigurerCusomizer;
import org.finesys.common.security.authorization.OAuth2TokenEndpointConfigurerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.core.OAuth2Token;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator;
import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator;
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 认证服务器配置
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
public class AuthorizationServerConfigure {

    private final PasswordDecoderFilter passwordDecoderFilter;

    /**
     * 授权服务过滤器链 匹配授权端点请求
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity httpSecurity, OAuth2AuthorizationService oAuth2AuthorizationService) throws Exception {
        // 配置授权服务器的安全策略，只有/oauth2/**的请求才会走如下的配置
        httpSecurity.regexMatcher("/oauth2/*");
        // 增加密码解密过滤器
        httpSecurity.addFilterBefore(passwordDecoderFilter, UsernamePasswordAuthenticationFilter.class);
        // 应用默认OAuth2AuthorizationServerConfigurer配置
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(httpSecurity);
        // 获取authorizationServerConfigurer
        OAuth2AuthorizationServerConfigurer auth2AuthorizationServerConfigurer = httpSecurity.getConfigurer(OAuth2AuthorizationServerConfigurer.class);
        // 配置授权服务器
        auth2AuthorizationServerConfigurer
                //令牌规则注入
                .tokenGenerator(oAuth2TokenGenerator())
                //tokenEndpoint配置
                .tokenEndpoint(new OAuth2TokenEndpointConfigurerCustomizer())
                // 客户端认证配置
                .clientAuthentication(new OAuth2ClientAuthenticationConfigurerCusomizer())
                // 授权服务
                .authorizationService(oAuth2AuthorizationService)
                //授权码端点个性化confirm页面
                .authorizationEndpoint(authorizationEndpoint -> authorizationEndpoint.consentPage(SecurityConstants.CUSTOM_CONSENT_PAGE_URI))
                //授权服务器设置
                .authorizationServerSettings(AuthorizationServerSettings.builder().issuer(SecurityConstants.PROJECT_LICENSE).build());
        //表单登录个性化
        new FormIdentityLoginConfigurer().init(httpSecurity);

        DefaultSecurityFilterChain securityFilterChain = httpSecurity.build();
        // 添加自定义的各种认证类型
        new AuthenticationProvidersCustomCustomizer().customize(httpSecurity);
        return securityFilterChain;
    }

    /**
     * 令牌生成规则实现 </br>
     * client:username:uuid
     *
     * @return OAuth2TokenGenerator
     */
    private OAuth2TokenGenerator<OAuth2Token> oAuth2TokenGenerator() {
        CustomeOAuth2AccessTokenGenerator accessTokenGenerator = new CustomeOAuth2AccessTokenGenerator();
        // 注入Token 增加关联用户信息
        accessTokenGenerator.setAccessTokenCustomizer(new CustomeOAuth2TokenCustomizer());
        return new DelegatingOAuth2TokenGenerator(accessTokenGenerator, new OAuth2RefreshTokenGenerator());
    }

}
